package spu

import (
	"context"
	"gorm.io/gorm"
	"mall/common/excption"
	constans "mall/services/product/rpc/consts"
	"mall/services/product/rpc/internal/domain/bo"
	"mall/services/product/rpc/internal/mapper"
	"mall/services/product/rpc/internal/mapper/entity"
	"time"

	"mall/services/product/rpc/internal/svc"
	"mall/services/product/rpc/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type ModifySpuLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewModifySpuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ModifySpuLogic {
	return &ModifySpuLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *ModifySpuLogic) ModifySpu(in *pb.ModifySpuDTO) (*pb.EmptyObj, error) {
	// 1.check spu info ...
	spuMapper := mapper.NewSpuMapper[entity.SpuEntity]()
	checkErr := l.checkRequestDTO(in, spuMapper)
	if checkErr != nil {
		return nil, checkErr
	}
	// 2.builder spu info obj to db update
	spuEntity, detailEntity := l.builderEntity(in)
	// 3.save db
	saveErr := l.saveDB(spuMapper, spuEntity, detailEntity)
	if saveErr != nil {
		return nil, saveErr
	}
	// 4.return obj
	return &pb.EmptyObj{}, nil
}

func (l *ModifySpuLogic) saveDB(spuMapper *mapper.SpuMapper[entity.SpuEntity], spuEntity entity.SpuEntity,
	detailEntity entity.SpuDetailEntity) error {
	detailMapper := mapper.NewSpuDetailMapper()
	saveErr := l.svcCtx.DBEngin.Transaction(func(tx *gorm.DB) error {
		// update info
		updateSpuInfoErr := spuMapper.UpdateCtx(l.ctx, tx, spuEntity)
		if updateSpuInfoErr != nil {
			return updateSpuInfoErr
		}
		// update detail
		updateSpuDetailErr := detailMapper.UpdateCtx(l.ctx, tx, detailEntity)
		if updateSpuDetailErr != nil {
			return updateSpuDetailErr
		}
		return nil
	})
	return saveErr
}

func (l *ModifySpuLogic) builderEntity(in *pb.ModifySpuDTO) (entity.SpuEntity, entity.SpuDetailEntity) {
	spuEntity := entity.SpuEntity{}
	spuEntity.BrandId = in.BrandId
	spuEntity.CategoryId = in.CategoryId
	spuEntity.ShopCategoryId = in.ShopCategoryId
	spuEntity.ShopId = in.ShopId
	spuEntity.Name = in.Name
	spuEntity.SellingPoint = in.SellingPoint
	spuEntity.MainImgUrl = in.MainImgUrl
	spuEntity.ImgUrls = in.ImgUrls
	spuEntity.Video = in.Video
	spuEntity.PriceFee = in.PriceFee
	spuEntity.MarketPriceFee = in.MarketPriceFee
	spuEntity.HasSkuImg = int64(in.HasSkuImg)
	spuEntity.Seq = int64(in.Seq)
	spuEntity.CategoryName = in.CategoryName
	spuEntity.BrandName = in.BrandName
	spuEntity.CategoryName = in.CategoryName
	spuEntity.ShopCategoryName = in.ShopCategoryName
	spuEntity.UpdateTime = time.Now()
	spuEntity.SpuId = in.SpuId
	// builder detail info obj to db update
	detailEntity := entity.SpuDetailEntity{}
	detailEntity.SpuId = in.SpuId
	detailEntity.Detail = in.Detail
	detailEntity.UpdateTime = time.Now()
	return spuEntity, detailEntity
}

func (l *ModifySpuLogic) checkRequestDTO(in *pb.ModifySpuDTO, spuMapper *mapper.SpuMapper[entity.SpuEntity]) error {
	spuBO := bo.SpuBO{SpuId: in.SpuId}
	selectCountCtx, err := spuMapper.SelectCountCtx(l.ctx, l.svcCtx.DBEngin, spuBO)
	if err != nil {
		return err
	}
	if selectCountCtx <= 0 {
		return excption.NewErrCode(constans.SpuInfoNoExistError)
	}
	spuBO = bo.SpuBO{Name: in.Name, NeStatus: constans.SpuTakeDown}
	selectOneCtx, err := spuMapper.SelectOneCtx(l.ctx, l.svcCtx.DBEngin, spuBO)
	if err != nil {
		return err
	}
	if selectOneCtx.SpuId > 0 && selectOneCtx.SpuId != in.SpuId {
		return excption.NewErrCode(constans.SpuNameRepeatError)
	}
	return nil
}
